package org.little.context.support;

import org.little.aop.aspectj.AspectJAutoProxyCreator;
import org.little.beans.factory.NoSuchBeanDefinitionException;
import org.little.beans.factory.annotation.AutowiredAnnotationProcessor;
import org.little.beans.factory.config.ConfigurableBeanFactory;
import org.little.beans.factory.support.DefaultBeanFactory;
import org.little.beans.factory.xml.XmlBeanDefinitionReader;
import org.little.context.ApplicationContext;
import org.little.core.io.Resource;
import org.little.util.ClassUtils;

import java.util.List;

/**
 * 引入 AbstractApplicationContext 将 DefaultBeanFactory 隐藏，不暴露到外面
 * @author Tinyspot
 * @date 2022-05-21 10:46
 */
public abstract class AbstractApplicationContext implements ApplicationContext {

    /**
     * 持有 DefaultBeanFactory
     */
    private DefaultBeanFactory factory = null;
    private ClassLoader beanClassLoader;

    /**
     * 公用的代码放到抽象类来做
     * @param configFile
     */
    public AbstractApplicationContext(String configFile) {
        factory = new DefaultBeanFactory();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
        Resource resource = this.getResourceByPath(configFile);
        reader.loadBeanDefinitions(resource);
        factory.setBeanClassLoader(this.getBeanClassLoader());
        registerBeanPostProcessor(factory);
    }

    @Override
    public Object getBean(String beanId) {
        return factory.getBean(beanId);
    }

    public void setBeanClassLoader(ClassLoader beanClassLoader) {
        this.beanClassLoader = beanClassLoader;
    }

    public ClassLoader getBeanClassLoader() {
        return this.beanClassLoader != null ? this.beanClassLoader : ClassUtils.getDefaultClassLoader();
    }

    /**
     * 模板方法模式
     * 抽象方法 - 交给子类实现
     * @param path
     * @return
     */
    protected abstract Resource getResourceByPath(String path);

    protected void registerBeanPostProcessor(ConfigurableBeanFactory beanFactory){
        AutowiredAnnotationProcessor postProcessor = new AutowiredAnnotationProcessor();
        postProcessor.setBeanFactory(beanFactory);
        beanFactory.addBeanPostProcessor(postProcessor);

        AspectJAutoProxyCreator proxyCreator= new AspectJAutoProxyCreator();
        proxyCreator.setBeanFactory(beanFactory);
        beanFactory.addBeanPostProcessor(proxyCreator);
    }

    @Override
    public Class<?> getType(String name) throws NoSuchBeanDefinitionException {
        return this.factory.getType(name);
    }

    @Override
    public List<Object> getBeansByType(Class<?> type) {
        return this.factory.getBeansByType(type);
    }
}
